#ifndef _SEMANTIC_GRAPH_SWIG__HPP__
#define _SEMANTIC_GRAPH_SWIG__HPP__

#include <iostream>
#include <vector>
#include <boost/graph/adjacency_list.hpp>

//---------------------

struct SemanticPoint  {
	std::vector<int> _data;
	SemanticPoint(int size) : _data(static_cast<std::size_t>(size),0) {
	}

	inline void reset(int size) {
		_data.resize(size);
		std::fill(_data.begin(),_data.end(),0);
	}

	inline int size() const {
		return _data.size();
	}	
	
	inline void set(int pos,int val) {
		_data[static_cast<std::size_t>(pos)] = val; 
	}

	inline int get(int pos) const {
		return _data[static_cast<std::size_t>(pos)];
	}
	inline bool operator<(SemanticPoint const & o) const
	{
		if (_data.size() == o._data.size())
		{
			for(std::size_t x =0; x < _data.size();++x)
			{	
				if(_data[x] == o._data[x]) continue;
				else return  (_data[x] < o._data[x]);
			}		
		}
		else return (_data.size() < o._data.size());
		return false;
	}
};

//---------------------

int value_compare(SemanticPoint const & a,SemanticPoint const & b);
inline int compare(SemanticPoint const & a,SemanticPoint const & b){ return  value_compare(a,b); }

//---------------------

struct NodeList {	
	std::vector<int> _data;
	NodeList() : _data(0) {} 
	int size() const { return static_cast<int>(_data.size()); }
	int get(int pos) { return _data[static_cast<std::size_t>(pos)]; }
	void append(int elem) { _data.push_back(elem); }
};

struct EdgeList {	
	std::vector<std::pair< std::pair<int,int >, int > > _data;
	EdgeList() : _data(0) {} 
	int size() const { return static_cast<int>(_data.size()); }
	int  getsrc(int pos) { return _data[static_cast<std::size_t>(pos)].first.first; }
	int  getdst(int pos) { return _data[static_cast<std::size_t>(pos)].first.second; }
	int  getw(int pos) { return _data[static_cast<std::size_t>(pos)].second; }
	void append(int src,int dst,int w) { _data.push_back( std::make_pair( std::make_pair(src,dst ), w ) ); }
};



//---------------------

struct NodeSet {	
	std::set<int> _data;
	NodeSet()  {} 
	int size() const { return static_cast<int>(_data.size()); }
	void add(int x) { _data.insert(x); }
	bool has(int x) const { return (_data.find(x) == _data.end()); }
	void remove(int x){ _data.erase(x);}
};

//---------------------

struct VertexData {
	SemanticPoint point;
	VertexData() : point(0) {}
};

struct EdgeData {
	int weight;
	EdgeData() : weight(0) {}	
};

struct SemanticGraph {
	
	//-------------------
	typedef boost::adjacency_list<boost::vecS,boost::vecS, boost::bidirectionalS, VertexData,EdgeData>   tGraphShortestpath; 
	typedef tGraphShortestpath::vertex_descriptor vertex_descriptor;
	typedef tGraphShortestpath::edge_descriptor edge_descriptor;
	
	typedef std::map< SemanticPoint,  tGraphShortestpath::vertex_descriptor > tmap; 
	//-------------------
	tGraphShortestpath g;
	tmap m;
	//-------------------
	SemanticGraph() {
	}
	
	int add_vertex( SemanticPoint const & p) {
		vertex_descriptor v;
		if( m.find(p) == m.end() ) {
			v = boost::add_vertex(g);
			g[v].point = p;
			m[p] = v; 	
		} else {
			v = m[p];
		}
		return static_cast<std::size_t>(v);
	}

	int get_vertex(SemanticPoint const & p) {
	vertex_descriptor v;
	tmap::const_iterator it = m.find(p);
		if(it == m.end() )  return -1;
		else return static_cast<std::size_t>(it->second);
	}

	void remove_vertex(int node) {
		vertex_descriptor v = static_cast<vertex_descriptor>(node);
		m.erase(g[v].point);
		boost::clear_vertex( v,g);
		boost::remove_vertex( v,g);
	}

	
	bool has_point(SemanticPoint const & p) const {
		return ( m.find(p) == m.end() );
	}
	
	SemanticPoint const & point(int node) const {
		tGraphShortestpath::vertex_descriptor  u =  static_cast<std::size_t>(node);
		return g[u].point;
	}

	//int add_edge(vertex_descriptor u,vertex_descriptor v,int edge_weight) {
	int add_edge(int src,int dst,int edge_weight) {
		tGraphShortestpath::vertex_descriptor  u =  static_cast<std::size_t>(src);
		tGraphShortestpath::vertex_descriptor  v =  static_cast<std::size_t>(dst);
		edge_descriptor e;
		bool ok = false;
		boost::tie(e,ok) = boost::add_edge(u,v,g);
		if(!ok) return 1;
		g[e].weight = edge_weight;
		return 0;
	}
	bool has_edge(int src,int dst) {
                tGraphShortestpath::vertex_descriptor  u =  static_cast<std::size_t>(src);
                tGraphShortestpath::vertex_descriptor  v =  static_cast<std::size_t>(dst);
                edge_descriptor e;
                bool ok = false;
                boost::tie(e,ok) = boost::edge(u,v,g);
        	return ok;
	}

	void remove_edge(int src,int dst) {
                tGraphShortestpath::vertex_descriptor  u =  static_cast<std::size_t>(src);
                tGraphShortestpath::vertex_descriptor  v =  static_cast<std::size_t>(dst);
		boost::remove_edge(u,v,g);	
	}

	int weight(int src,int dst) {
		tGraphShortestpath::vertex_descriptor  u =  static_cast<std::size_t>(src);
		tGraphShortestpath::vertex_descriptor  v =  static_cast<std::size_t>(dst);
		edge_descriptor e;
		bool ok = false;
		boost::tie(e,ok) = boost::edge(u,v,g);
		if(!ok) return -1;
		return g[e].weight;
	}

	int num_vertices() {
		return static_cast<int>(boost::num_vertices(g));
	}

	void neighbors(int node, NodeList & n) {
		tGraphShortestpath::out_edge_iterator  it;
		tGraphShortestpath::out_edge_iterator  end;
		tGraphShortestpath::vertex_descriptor  u =  static_cast<std::size_t>(node);
		for(boost::tie(it,end) = boost::out_edges(u,g);it != end;++it) {
			edge_descriptor e = (*it);
			vertex_descriptor v = boost::target(e,g);
			n.append(v);
		}
	}
	void neighbors_weight(int node, NodeList & n,int wei) {
		tGraphShortestpath::out_edge_iterator  it;
		tGraphShortestpath::out_edge_iterator  end;
		tGraphShortestpath::vertex_descriptor  u =  static_cast<std::size_t>(node);
		for(boost::tie(it,end) = boost::out_edges(u,g);it != end;++it) {
			edge_descriptor e = (*it);
			vertex_descriptor v = boost::target(e,g);
			int w  = boost::get(boost::get(&EdgeData::weight,g),e);
			if(w != wei) continue;
			n.append(v);
		}
	}
	bool has_neighbor_weight(int node,int wei) {
		tGraphShortestpath::out_edge_iterator  it;
		tGraphShortestpath::out_edge_iterator  end;
		tGraphShortestpath::vertex_descriptor  u =  static_cast<std::size_t>(node);
		for(boost::tie(it,end) = boost::out_edges(u,g);it != end;++it) {
			edge_descriptor e = (*it);
			int w  = boost::get(boost::get(&EdgeData::weight,g),e);
			if(w == wei) return true;
		}
		return false;
	}

	void iter_edges(EdgeList & l) {
		tGraphShortestpath::edge_iterator it,end;
		for(boost::tie(it,end) = boost::edges(g);it != end;++it)
		{
			edge_descriptor e = (*it);
			int w  = boost::get(boost::get(&EdgeData::weight,g),e);
			vertex_descriptor u = boost::source(e,g);
			vertex_descriptor v = boost::target(e,g);
			l.append( static_cast<std::size_t>(u),static_cast<std::size_t>(v),w);
		}
	}	

	int out_degree(int node) {

		vertex_descriptor v = static_cast<vertex_descriptor>(node);
		return static_cast<int>(boost::out_degree(v,g));
	} 	

};

/*
void boost_semantic_all_parents_query(SemanticGraph const & g,NodeList const & external_nodes,EdgeList const & source_and_dest,SemanticPoint const & query);
*/
#endif
